//
//  URL.h
//  sad
//
//  Created by Christopher Kemsley on 2/9/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#ifndef sad_URL_h
#define sad_URL_h

#include <string>
#include <map>




/*
 Notes for file URLs:
 
 Unless explicitely specified as a directory, the URL will be
 assumed to be a file URL unless the last character is a '/'
 
 Some examples of inputs and how they're interpreted are as follows:
 
 
 Input:			file://localhost/Path/To/File.txt
 Scheme:		file
 Host:			localhost
 Path:			/Path/To/File.txt
 isDirectory:	false
 isAbsolute:	true
 
 
 Input:			file://localhost/Path/To/
 Scheme:		file
 Host:			localhost
 Path:			/Path/To/
 isDirectory:	true
 isAbsolute:	true
 
 
 Input:			file://localhost/Path/To
 Scheme:		file
 Host:			localhost
 Path:			/Path/To
 isDirectory:	false
 isAbsolute:	true
 
 
 Input:			file://localhost/Path/To , true
 Scheme:		file
 Host:			localhost
 Path:			/Path/To/
 isDirectory:	true
 isAbsolute:	true
 
 
 
 Input:			file:/Path/To/File.txt
 Scheme:		file
 Host:			localhost
 Path:			/Path/To/File.txt
 isDirectory:	false
 isAbsolute:	true
 
 Input:			file:Path/To/File.txt
 Scheme:		file
 Host:			localhost
 Path:			Path/To/File.txt
 isDirectory:	false
 isAbsolute:	false
 
 Input:			/Path/To/File.txt
 Scheme:		file
 Host:			localhost
 Path:			/Path/To/File.txt
 isDirectory:	false
 isAbsolute:	true
 
 Input:			Path/To/File.txt
 Scheme:		file
 Host:			localhost
 Path:			Path/To/File.txt
 isDirectory:	false
 isAbsolute:	false
 */





struct	URL
{
	
	
	/* Creates a URL stub */
	URL		() ;
	
	/* Directly initializes elements */
	URL		( std::string const & inScheme , std::string const & inHost , std::string const & inPath ) ;
	
	/* Creates the URL by decoding the input */
	URL		( std::string const & inURL ) ;			// "file://localhost/a/b/filename.xml" or "a/b/"
	URL		( char const * inURL ) ;				// "file://localhost/a/b/filename.xml" or "a/b/"
	URL		( URL const & inURL ) ;					// "file://localhost/a/b/filename.xml" or "a/b/"
	
	/* Creates the URL and forces it to be a directory if isDirectory=true */
	URL		( std::string const & inURL , bool isDirectory ) ;
	URL		( char const * inURL , bool isDirectory ) ;
	
	/* Appends the path to the base URL */
	URL		( URL const & inBaseURL , std::string const & inPath ) ;
	URL		( URL const & inBaseURL , char const * inPath ) ;
	
	/* Appends the path to the base URL and forces it to be a directory if isDirectory=true */
	URL		( URL const & inBaseURL , std::string const & inPath , bool isDirectory ) ;
	URL		( URL const & inBaseURL , char const * inPath , bool isDirectory ) ;
	
	
	
	/* Queries */
	URL const			absoluteURL () const ;
	std::string const	string () const ;			// "file://localhost/a/b/filename.xml" or "file:a/b/"
	std::string const	absoluteString () const ;	// "file://localhost/a/b/filename.xml" or "file://localhost/base/path/a/b/"
	std::string const	absolutePath () const ;		// "/a/b/filename.xml" or "/base/path/a/b/"
	
	std::string const&	scheme () const ;			// "file" or "file" (or "http")
	std::string const&	host () const ;				// "localhost" or "localhost" (or "www.apple.com")
	std::string const&	path () const ;				// "/a/b/filename.xml" or "a/b/"
	std::string const	filename () const ;			// "filename.xml" or ""
	std::string const	fileExtension () const ;	// "xml" or ""
	
	bool				isDirectory () const ;		// false or true
	bool				isAbsolute () const ;		// true or false
	
	URL const			directoryURL () const ;		// "file://localhost/a/b/" or "file://localhost/base/path/a/b/"
	
	
	
	/* Setting */
	URL&		operator= ( std::string const & inURL ) ;
	URL&		operator= ( char const * inURL ) ;
	URL&		operator= ( URL const & inURL ) ;
	
	void		setScheme	( std::string const & value ) ;
	void		setHost		( std::string const & value ) ;
	void		setPath		( std::string const & value ) ;
	
	
	
	/* Comparing */
	bool		operator==	( URL const & inURL ) const ;
	bool		operator==	( char const * inURL ) const ;
	bool		operator==	( std::string const & inURL ) const ;
	
	bool		operator<	( URL const & inURL ) const ;
	bool		operator>	( URL const & inURL ) const ;
	
	
	
	/* Changing the global base-URL for URL expansion */
	void		makeBaseURL () const ; // makes this the base-path for this scheme/host
	
	
	
	
	
private:
	friend std::ostream& operator<<	( std::ostream & stream , URL const & url ) ;
	
	std::string	mScheme ;		// "file"				"file"
	std::string	mHost ;			// "localhost"			"localhost"
	std::string	mPath ;			// "/a/b/filename.xml"	"a/b"
	
	void	_decode					( std::string const & url , bool assumeIsDirectory = false ) ;
	void	_decode_breakout		( std::string const & url ) ;
	void	_decode_colon_host		( std::string const & url , size_t colonLocation ) ;
	void	_decode_colon_noHost	( std::string const & url , size_t colonLocation ) ;
	void	_decode_noColon_noHost	( std::string const & url ) ;
	
	
	/* This is how we manage the baseURLs */
	typedef std::map<std::string,std::string>	HostToPathMap ;
	typedef std::map<std::string,HostToPathMap>	SchemeToHTPMap ;
	
	static SchemeToHTPMap&	_baseURLInfo () ;
} ;

#endif
